package com.vertxsample.samples.testweb

import com.vertxsample.samples.core.db.HikariPoolUtil
import com.vertxsample.samples.core.web.RequestContext
import com.vertxsample.samples.core.web.annotation.ClassUtils
import com.vertxsample.samples.core.web.annotation.HttpAPI
import com.vertxsample.samples.core.web.annotation.HttpController
import com.zaxxer.hikari.HikariConfig
import io.vertx.core.AbstractVerticle
import io.vertx.core.Future
import io.vertx.core.Handler
import io.vertx.core.Vertx
import io.vertx.core.http.HttpServerResponse
import io.vertx.core.json.JsonObject
import io.vertx.ext.web.Router
import io.vertx.ext.web.RoutingContext
import io.vertx.ext.web.handler.StaticHandler
import org.apache.logging.log4j.LogManager
import org.jooq.DSLContext
import java.lang.reflect.Method
import java.util.concurrent.CompletableFuture


class StarterVerticle(val options :JsonObject) : AbstractVerticle() {
    val logger = LogManager.getLogger(StarterVerticle::class.java!!.getName())

    override fun start(startFuture: Future<Void>) {




        //启动web
        startServer(startFuture ,options);




    }

    fun  startServer(startFuture:Future<Void>,options :JsonObject){
        var router = customRouter(vertx,options)
        println("server running on 8888")
        vertx.createHttpServer().requestHandler({ handler -> router.handle(handler)}).listen(8888){ result ->
            if (result.succeeded()) {
                startFuture.complete()
            } else {
                startFuture.fail(result.cause())
            }
        }
    }

    fun customRouter(vertx : Vertx,options :JsonObject) : Router {


        //数据配置
        val config = HikariConfig()


        config.jdbcUrl =options.getString("datasource.url")
        config.username = options.getString("datasource.username")
        config.password = options.getString("datasource.password")
        config.driverClassName = options.getString("datasource.driver-class-name")

        config.addDataSourceProperty("cachePrepStmts", "true")
        config.addDataSourceProperty("prepStmtCacheSize", "250")
        config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048")

        val dslContext= HikariPoolUtil.getContext(HikariPoolUtil.getConnection(HikariPoolUtil.getDataSource(config))!!)

        var router = Router.router(vertx)
        try {
            //根据注解设置路由
            configRouterByannotation(router, dslContext);
        }catch (e:Exception){
            logger.error("",e)
        }
        //静态页面配置
        val staticHandler = StaticHandler.create("src/main/webapp")
        router.route("/*").handler(staticHandler);


        return router
    }
    //根据注解设置路由
    fun configRouterByannotation(router:Router,dslContext:DSLContext){
        ClassUtils.scanPackageByAnnotation("com.vertxsample.samples.testweb.controller",false,HttpController::class.java ).stream()
            .forEach { c->


                  val routerUri1=c.getAnnotation(HttpController::class.java).routerUri;
                  ClassUtils.scanFunctionByAnnotation(c,HttpAPI::class.java).stream()
                      .forEach {
                          m->

                              val api=m.getDeclaredAnnotation(HttpAPI::class.java);
                              logger.info("mapping url:"+ routerUri1+ api.routerUri +" to "+c.name+"."+m.name)
                              router.route(routerUri1+ api.routerUri).handler(HttpHandler(c,m,api,vertx,dslContext));


                      }
             }
    }



    class HttpHandler(val controllerClass : Class<*>, val method : Method, val api:HttpAPI, val vertx :Vertx, val dslContext: DSLContext): Handler<RoutingContext> {
        override fun handle(routingContext: RoutingContext?) {
            val controller=controllerClass.getConstructor(RequestContext::class.java).newInstance(RequestContext(vertx,
                routingContext!!,dslContext))

            val  future=method.invoke(controller) as CompletableFuture<String>
            if(api.returnType=="json") {
                future.thenAccept { it ->
                    routingContext.response().json().end(it)
                }
            }else
                if(api.returnType=="html") {
                    future.thenAccept { it ->
                        routingContext.response().html().end(it)
                    }
                }

        }
        fun HttpServerResponse.json() : HttpServerResponse {
            return this.putHeader("content-type","application/json; charset=utf-8")
        }
        fun HttpServerResponse.html() : HttpServerResponse {
            return this.putHeader("content-type","text/html")
        }

    }
}